package net.gazhi.delonix.grac.service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.gazhi.delonix.core.form.TreeNodeMoveForm;
import net.gazhi.delonix.core.service.AbstractEntityService;
import net.gazhi.delonix.core.service.SimpleTreeNodeService;
import net.gazhi.delonix.grac.entity.gru.User;
import net.gazhi.delonix.grac.entity.gru.UserDir;
import net.gazhi.delonix.grac.form.UserDirEditForm;

import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;

@Service
@Transactional(readOnly = true)
public class UserDirService extends AbstractEntityService<UserDir> {

	@Autowired
	private SimpleTreeNodeService simpleTreeNodeService;

	@SuppressWarnings("unchecked")
	public List<UserDir> listAll() {
		return super.createCriteria().addOrder(Order.asc("fullOrder")).list();
	}

	/**
	 * 保存目录(新增/修改)
	 * 
	 * @param form
	 * @param result
	 */
	@Transactional
	public void save(UserDirEditForm form, BindingResult result) {
		UserDir dir = null;
		if (form.getId() != null) {
			if (new Long(1).equals(form.getId())) {
				result.rejectValue("id", "RootLocked", "Can NOT Modify Root Directory!");
				return;
			}
			// 修改
			dir = this.get(form.getId());
			if (dir == null) {
				result.rejectValue("id", "NotFound", new String[] { String.valueOf(form.getId()) }, "Directory NOT Found!");
				return;
			}
			UserDir parent = dir.getParent();
			// 重名验证
			Map<String, Object> propertyMap = new HashMap<String, Object>();
			propertyMap.put("parent", parent);
			propertyMap.put("nameZh", form.getNameZh());
			if (super.otherExisted(form.getId(), propertyMap)) {
				result.rejectValue("nameZh", "Exists", new Object[] { form.getNameZh() }, "Chinese-Name already exists!");
				return;
			}
			propertyMap.remove("nameZh");
			propertyMap.put("nameEn", form.getNameEn());
			if (super.otherExisted(form.getId(), propertyMap)) {
				result.rejectValue("nameEn", "Exists", new Object[] { form.getNameEn() }, "English-Name already exists!");
				return;
			}
		} else {
			// 新增
			UserDir parent = this.get(form.getParentId());
			// 验证上级目录
			if (parent == null) {
				result.rejectValue("parentId", "NotFound", new String[] { String.valueOf(form.getParentId()) }, "Parent Directory NOT Found!");
				return;
			}
			// 重名验证
			Map<String, Object> propertyMap = new HashMap<String, Object>();
			propertyMap.put("parent", parent);
			propertyMap.put("nameZh", form.getNameZh());
			if (super.otherExisted(form.getId(), propertyMap)) {
				result.rejectValue("nameZh", "Exists", new Object[] { form.getNameZh() }, "Chinese-Name already exists!");
				return;
			}
			propertyMap.remove("nameZh");
			propertyMap.put("nameEn", form.getNameEn());
			if (super.otherExisted(form.getId(), propertyMap)) {
				result.rejectValue("nameEn", "Exists", new Object[] { form.getNameEn() }, "English-Name already exists!");
				return;
			}
			dir = new UserDir();
			dir.setParent(parent);
			dir.setShowOrder(simpleTreeNodeService.generateOrder(dir));
		}
		// 拷贝属性，然后执行保存
		BeanUtils.copyProperties(form, dir);
		if (dir.getId() == null) {
			dao.save(dir);
			simpleTreeNodeService.updateFullIdAndOrder(dir);
		} else {
			dao.update(dir);
		}
	}

	/**
	 * 删除目录
	 * 
	 * @param id
	 * @param result
	 */
	@Transactional
	public void delete(Long id, BindingResult result) {
		if (id == null || id.longValue() < 2) {
			result.rejectValue("id", "Invalid", new Object[] { id }, "Invalid Parameter: id=" + id);
			return;
		}
		UserDir dir = this.get(id);
		if (dir == null) {
			result.rejectValue("id", "Invalid", new Object[] { id }, "Invalid Parameter: id=" + id);
			return;
		}
		if (dir.getChildren().size() > 0) {
			result.reject("ChildExists", "Child directory exists!");
			return;
		}
		Number userId = (Number) dao.createCriteria(User.class).add(Restrictions.eq("userDir", dir)).setMaxResults(1).setProjection(Projections.id()).uniqueResult();
		if (userId != null && userId.longValue() > 0L) {
			result.reject("UserExists", "User exists under this directory!");
			return;
		}
		dao.delete(dir);
	}

	/**
	 * 移动目录
	 * 
	 * @param form
	 * @param result
	 */
	@Transactional
	public void move(TreeNodeMoveForm form, BindingResult result) {

		if (form.getId() < 2) {
			result.rejectValue("id", "Invalid", new Object[] { form.getId() }, "Invalid Parameter: id=" + form.getId());
			return;
		}
		UserDir node = this.get(form.getId());
		if (node == null) {
			result.rejectValue("id", "Invalid", new Object[] { form.getId() }, "Invalid Parameter: id=" + form.getId());
			return;
		}
		UserDir target = this.get(form.getTargetId());
		if (target == null) {
			result.rejectValue("targetId", "Invalid", new Object[] { form.getId() }, "Invalid Parameter: targetId=" + form.getTargetId());
			return;
		}

		// 重名验证
		UserDir parent = "inner".equals(form.getMoveType()) ? target : target.getParent();
		if (parent != node.getParent()) {
			Map<String, Object> propertyMap = new HashMap<String, Object>();
			propertyMap.put("parent", parent);
			propertyMap.put("nameZh", node.getNameZh());
			if (super.otherExisted(form.getId(), propertyMap)) {
				result.rejectValue("nameZh", "Exists", new Object[] { node.getNameZh() }, "Chinese-Name already exists in target position!");
				return;
			}
			propertyMap.remove("nameZh");
			propertyMap.put("nameEn", node.getNameEn());
			if (super.otherExisted(form.getId(), propertyMap)) {
				result.rejectValue("nameEn", "Exists", new Object[] { node.getNameEn() }, "English-Name already exists in target position!");
				return;
			}
		}

		if (!this.simpleTreeNodeService.move(node, target, form.getMoveType())) {
			result.reject("Unknow", "Unknow error!");
		}
	}

}
